﻿<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<title>OpenGLMd5</title>
<link rel="stylesheet" type="text/css" href="./css/stdoc.css"/>
<script type="text/javascript" src="./js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="./js/stdoc.js"></script>
</head>
<body>
<div id="div_model" style="display:none">SINGLE</div>
<div id="div_body">
<div id="div_logo"></div>
<div id="div_left">
<div id="div_left_list">
<ul class='ul_group_root'>
<li>
    <a class='a_node_root anchor_btn' name='a_a' href='#a_a'>密码碰撞可以有多非主流？</a>
    <ul>
        <li class='li_node_sub'><a class='anchor_btn' name='a_b' href='#a_b'>起因</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_c' href='#a_c'>OpenGL简介</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_d' href='#a_d'>图形渲染管线</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_e' href='#a_e'>着色器</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_f' href='#a_f'>你好三角形</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_g' href='#a_g'>思路分析</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_h' href='#a_h'>MD5算法</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_i' href='#a_i'>计算过程</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_j' href='#a_j'>批量计算</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_k' href='#a_k'>试验效果</a></li>
        <li class='li_node_sub'><a class='anchor_btn' name='a_l' href='#a_l'>优化方案</a></li>
    </ul>
</li>
</ul><div class='div_left_space_space'></div>
</div>
<span id="span_time">2022-12-07 -> by:<span>DebugST</span></span>
</div>
<div id="div_right">
<h1 class='h_title anchor_point' name='a_a'>密码碰撞可以有多非主流？</h1>
<p>在日常的渗透过程中难为会遇到要破解密码的时候，比如<span class='mark'>MD5</span>，通常我们可能会在一些网站上先检索一番，如果没有结果的话可能我们就会拿出神器<span class='mark'>Hashcat</span>碰撞。</p>
<p>一提到<span class='mark'>Hashcat</span>大家的第一反应就是。。。快。。。那么它为什么会这么快呢？？？🤔🤔🤔🤔🤔</p>
<p>所以说到这里你会不会以为作者今天是想要去分析<span class='mark'>Hashcat</span>的原理或代码？。。不不不。。今天作者要玩一次非主流。</p>
<div class='div_hightlight' style='background-color:pink;color:black'>
<p>警告：此文会很长。且此文将以<span class='mark'>MD5</span>的碰撞作为案例。仅提供思路<span class='mark'>Demo</span>。并没有现成的工具，作者也并不打算编写成工具，难道<span class='mark'>Hashcat</span>它不香吗？</p>
</div>
<p>项目(OpenGLForHash)地址: <a class='mark' target='_blank' href='https://github.com/DebugST/OpenGLForHash'>GitHub</a> <a class='mark' target='_blank' href='https://gitee.com/DebugST/OpenGLForHash'>Gitee</a></p>
<div><h2 class='h_option anchor_point' name='a_b'>起因</h2></div>
<p>因为一些机缘巧合，作者接触到了<span class='mark'>OpenGL</span>，并且心血来潮的作者做了一个烂尾工程<a class='mark' target='_blank' href='https://github.com/DebugST/STGL'>STGL</a></p>
<p>一个作者自己移植的<span class='mark'>.Net</span>版本的<span class='mark'>OpenGL</span>封装。之所以说是烂尾工程是因为作者从移植完毕后就没再动过这个项目了，教程也只写了一个章节：<a class='mark' target='_blank' href='https://debugst.github.io/STGL/'>教程</a></p>
<p>作者在学习<span class='mark'>OpenGL</span>的过程中，当编写第一个<span class='mark'>Shader</span>(着色器)的时候就开始有点想入非非了。。为什么？。。<span class='mark'>Shader</span>程序是运行在<span class='mark'>GPU</span>上的代码片段。那时候作者就在想，既然可以编写运行在<span class='mark'>GPU</span>上的代码，那么是不是可以干点别的？不过当时只是埋下了一个种子，并没有多想。</p>
<p>随着后来学习的深入，不仅对<span class='mark'>OpenGL</span>了解越来越多。对显卡的工作原理也开始渐渐清晰，直到有一天作者挺好奇的跨越了一些学习步骤。直接从<span class='mark'>Blender</span>导出了一个<span class='mark'>3D</span>模型的<span class='mark'>obj</span>文件。然后自己解析，并将数据送给<span class='mark'>OpenGL</span>的接口的时候。作者震惊了，虽说不是多大的模型，几万个顶点，以线框模式绘制，并且不停的旋转。几十帧的帧率。。电脑风扇都不带转的。这是作者以前在使用<span class='mark'>GDI</span>想都不敢想的事情。那个时候作者就慢慢开始思考关于<span class='mark'>并行运算</span>的问题。</p>
<p>作为网络安全的打工仔，很自然的就联想到利用<span class='mark'>GPU</span>碰撞密码这种事情，也很自然的就想到了<span class='mark'>Hashcat</span>，并且思考<span class='mark'>Hashcat</span>是如何实现的。不过作者并没有第一时间去看<span class='mark'>Hashcat</span>的源码。而是在思考以当前的思考角度出发，自己能不能做一个<span class='mark'>Hashcat</span>。然后脑洞打开的时候就到了。</p>
<div><h2 class='h_option anchor_point' name='a_c'>OpenGL简介</h2></div>
<p>在还没有接触到<span class='mark'>OpenGL</span>之前，作者一直以为<span class='mark'>OpenGL</span>是一个<span class='mark'>SDK</span>需要安装各种东西，然后才可以进行相关的开发。事实上并非如此。基本上现在大多数的电脑都可以直接运行<span class='mark'>OpenGL</span>程序。</p>
<img src='./images/opengl.log.jpeg'/>
<p><span class='mark'>OpenGL</span>并不是一个<span class='mark'>SDK</span>而是一个<span class='mark'>API</span>规范，由<span class='mark'>khronos</span>组织所维护的一套编程接口标准。它们规定了一些3D实时渲染所需要的基本函数的名称以及需要的参数和输出值。至于功能怎么实现。。。这个是硬件的事情了是吧？也就是显卡而不关<span class='mark'>khronos</span>什么事情。就好比定义<span class='mark'>HTTP</span>协议规范的人，他们不可能要自己去做一个浏览器吧？</p>
<p>如果一个显卡生产厂商愿意去支持<span class='mark'>OpenGL</span>的规范，那么他们就会去实现那些<span class='mark'>API</span>接口，然后将这些实现好的接口伴随着驱动程序一起安装在系统中。而基本显卡厂商都愿意去实现这些<span class='mark'>API</span>，不然都不好意思说自己的显卡有多牛逼，所以基本上每个系统中都天然拥有<span class='mark'>OpenGL</span>的运行环境。不会吧？不会你的电脑上连显卡驱动都没装吧？</p>
<p>至于如何调用<span class='mark'>OpenGL</span>这是属于另一个问题了。这里不做过多的描述，有兴趣的同学可以看看这里：<a class='mark' target='_blank' href='https://debugst.github.io/STGL/?id=1.1'>传送门</a></p>
<p>如果你是windows系统的话，我猜在你的系统目录下肯定有一个<span class='mark'>opengl32.dll</span>🤫🤫🤫🤫🤫并且从<span class='mark'>Win98</span>时代开始他就一直存在，且没有更新过😂😂😂。</p>
<p>微软：我巴不得弄死它。。当我的<span class='mark'>DirectX</span>不存在？。。要不是弄不死它并且为了实现规范。。你以为我会放个<span class='mark'>opengl32.dll</span>在那里？？？</p>
<div><h2 class='h_option anchor_point' name='a_d'>图形渲染管线</h2></div>
<p>也不知道有没有写代码的小伙伴接触过图形相关的函数，比如<span class='mark'>windows</span>上的<span class='mark'>GDI</span>。这类图形库基本都有提供类似于<span class='mark'>DrawXXX</span>之类的函数。比如绘制一个矩形可能会有这样一个函数:</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>void</span> <span style='color:rgba(255,0,255,1)'>DrawRectangle</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,0,1)'>/*other params,*/</span> <span style='color:rgba(100,149,237,1)'>float</span> x<span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(100,149,237,1)'>float</span> y<span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(100,149,237,1)'>float</span> width<span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(100,149,237,1)'>float</span> height<span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>当然可能还有<span class='mark'>DrawLine</span><span class='mark'>DrawBezier</span>之类的函数，但是这些函数或许可以满足一些规则几何图形的绘制，对于不规则的几何图像可能会提供一个类似于这样的函数：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>void</span> <span style='color:rgba(255,0,255,1)'>DrawPath</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,0,1)'>/*other params,*/</span> <span style='color:rgba(0,255,255,1)'>Point</span><span style='color:rgba(255,255,255,1)'>[]</span> pts<span style='color:rgba(255,255,255,1)'>)</span></pre>
</div>
<p>对于规则的我们可能直接就把坐标传入给函数，对于不规则的则是直接传入一组坐标，因为任何图形都可以被拆解成很多条线段组成。这是在平面绘图的情况下，但是<span class='mark'>OpenGL</span>是一个<span class='mark'>三维</span>的接口。当然<span class='mark'>三维</span>的世界中也有很多规则物体，但是更多的是不规则物体，所以在<span class='mark'>OpenGL</span>的接口中并没有设计类似于<span class='mark'>DrawCube</span>之类的函数，而是直接采用通用方案，接收顶点。那么一个<span class='mark'>三维</span>图形是如何本渲染出来到显示器上的画面的？</p>
<img src='./images/pipeline.png'/>
<p>上面就是一个<span class='mark'>OpenGL</span>的渲染流程，一个显卡的工程流程也差不多就是如此。其中<span class='mark'>vertex data</span>就是要送入显卡的数据，比如三维模型的坐标顶点。比如我们希望在三维空间中绘制一个三角形可能就会送入如下数据。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>[]</span> vertices <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第一个顶点</span>
<span class='span_code_line'></span>     <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第二个顶点</span>
<span class='span_code_line'></span>     <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span>  <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span>  <span style='color:rgba(0,255,0,1)'>// 第三个顶点</span>
<span class='span_code_line'></span><span style='color:rgba(255,255,255,1)'>};</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>/* 这里采用的是归一化空间中标(右手坐标系)
<span class='span_code_line'></span> * OpenGL的归一化空间是一个2*2*2的立方体中心是原点坐标。立方体正面和UI界面形成映射关系。
<span class='span_code_line'></span> * 关于归一化空间，这里不做过多介绍。理解为UI窗口左上角是(-1,1,1)右下角是(1,-1,1)就行了。
<span class='span_code_line'></span> */</span></pre>
</div>
<p>然后将他送入到显存中，然后紧接着<span class='mark'>顶点着色器</span>会率先处理这些顶点坐标，直到最终画面在显示器上呈现。可以看到上图大概有6个步骤，其中蓝色部分是需要编写<span class='mark'>着色器代码</span>的。而对于<span class='mark'>OpenGL</span>而言<span class='mark'>顶点着色器</span>和<span class='mark'>片段着色器</span>是必须的，没有默认处理方式。<span style='color:gray'>(当然在老版本的<span class='mark'>OpenGL</span>接口中是没有渲染管线的，在<span class='mark'>3.2</span>版本的接口以前是<span class='mark'>立即渲染模式</span>这里不做过多介绍)</span></p>
<div><h2 class='h_option anchor_point' name='a_e'>着色器</h2></div>
<p><span class='mark'>顶点着色器</span>(Vertex Shader)是对传入的<span class='mark'>verte data</span>做预处理，比如传入了一个三维模型的数据进去(以上面的<span class='mark'>vertices</span>为例)，想将模型向上移动一个单位你认为应该怎么做？</p>
<p>你会不会认为修改<span class='mark'>vertices</span>的数据后然后重新传入显存？。。比如：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>for</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>int</span> i <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>i <span style='color:rgba(255,255,255,1)'>&lt;</span> vertices<span style='color:rgba(112,128,144,1)'>.Length</span><span style='color:rgba(255,255,255,1)'>;</span>i<span style='color:rgba(255,255,255,1)'>+=</span><span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>){</span>
<span class='span_code_line'></span>    vertices<span style='color:rgba(255,255,255,1)'>[</span>i <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>+=</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>;</span> <span style='color:rgba(0,255,0,1)'>// y坐标</span>
<span class='span_code_line'></span><span style='color:rgba(255,255,255,1)'>}</span></pre>
</div>
<p>是的，其实这样做也没毛病，但是如果<span class='mark'>vertices</span>不止3个顶点而是3W个顶点呢？并且不是只向上移动一个单位，而是以每秒一个单位的速度往上移动并且每秒24帧呢？那么上面的代码需要每秒执行24次并且每次<span class='mark'>Y</span>坐标增加<span class='mark'>1/24</span>，我猜按照上面的代码去处理的话，估计<span class='mark'>CPU</span>距离<span class='mark'>100%</span>已经不远了。</p>
<p>但是你有没有想过其实上面的每个顶点都是独立的，将第一个顶点的<span class='mark'>Y</span>坐标加上<span class='mark'>n</span>并不影响第二个顶点的<span class='mark'>Y</span>加上<span class='mark'>n</span>后的结果，也就是说它们的计算过程都是独立的并不依赖先前的计算。也就是说，即便3W个顶点同时计算<span class='mark'>Y</span>加上<span class='mark'>n</span>也没有任何问题。而这正是顶点着色器的作用。所以在一些游戏开发中，传入显存的数据都是模型的基本数据，至于游戏中物体的移动全在顶点着色器中完成。<span style='color:pink'><span class='mark'>顶点着色器</span>是并行运算的且由<span class='mark'>GPU</span>执行，每个顶点都会被分配到一个<span class='mark'>顶点着色</span>器代码片段中，而上面的代码则是在<span class='mark'>CPU</span>中执行。</span>至于<span class='mark'>CPU</span>和<span class='mark'>GPU</span>的区别这里就不介绍了。</p>
<p><span class='mark'>顶点着色器</span>处理完一个顶点就会继续往下传递，接下来的<span class='mark'>图元装配</span>和<span class='mark'>几何着色器</span>这里就不做介绍了。接下来就是<span class='mark'>栅格化</span>的过程，也就是说生成二维的像素点。毕竟显示器上显示的画面终究还是二维的，可以看到渲染管线图中传入的是一个三角形的顶点，到了<span class='mark'>栅格化</span>后，显卡补差生成了很多像素点。最后这些像素点会传递给<span class='mark'>片段着色器</span></p>
<p><span class='mark'>片段着色器</span>(Fragment Shader)是一个很重要的过程，如果说<span class='mark'>栅格化</span>是生成了像素点，那么<span class='mark'>片段着色器</span>就是为像素点上色的过程，而这直接决定了最后显示效果的质量，这就是为么有些游戏画面看起来很真实，而有些画面惨不忍睹。如何上色这个过程是需要通过自己写算法去完成的，比如光影追踪什么的。当然<span class='mark'>片段着色器</span>也是运行在<span class='mark'>GPU</span>之上的。</p>
<p>到了最后就是<span class='mark'>测试与混合</span>，比如三维场景中会有很多元素，哪些元素在前哪些在后，或者说哪些是带有<span class='mark'>Alpha</span>通道的。处理完这些，一帧二维图像就渲染完成了。</p>
<div><h2 class='h_option anchor_point' name='a_f'>你好三角形</h2></div>
<p>可能读到这里你会不会认为已经跑题了？不是说跑碰撞密码的吗？怎么扯上三维图像的渲染了？没错。。。作者就是想利用上面这一套机制去碰撞密码。所以必须对<span class='mark'>OpenGL</span>做一些基本的介绍，并且接下来还有用一个完整案例做一个三角形的渲染，就像刚开始写代码一样我们会写一个<span class='mark'>Hello World</span>，我们会先写一个<span class='mark'>Hello Triangle</span>来做一个完整流程，再继续替换里面的代码，最终完成<span class='mark'>MD5</span>的碰撞。</p>
<p>接下来的代码将采用<a class='mark' target='_blank' href='https://github.com/DebugST/STGL'>STGL</a>为基础进行编写，当然首先我们需要创建一个窗口，因为我们需要绑定<span class='mark'>OpenGL</span>的<span class='mark'>Context</span>。就好比在<span class='mark'>Windows</span>中使用<span class='mark'>GDI</span>需要一个<span class='mark'>HDC</span>一样，至于如何绑定<span class='mark'>Context</span>这里并不做介绍，只介绍关键代码。最终的<span class='mark'>Demo</span>可以参考<span class='mark'>GitHub</span>仓库，代码已经添加详细注释。</p>
<p>首先我们需要准备一组数据，就以上面的<span class='mark'>vertices</span>为例，然后我们需要将它送入显存。在那之前我们需要现在显存中创建一个对象，一个<span class='mark'>VAO</span>对象(Vertex Array Object)。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>uint</span> vao <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.GenVertexArrays</span><span style='color:rgba(255,255,255,1)'>();</span>    <span style='color:rgba(0,255,0,1)'>// 创建VAO，可理解为创建了一个模型对象</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BindVertexArray</span><span style='color:rgba(255,255,255,1)'>(</span>vao<span style='color:rgba(255,255,255,1)'>);</span>            <span style='color:rgba(0,255,0,1)'>// 将此对象绑定到当前操作的上下文</span></pre>
</div>
<p>一个<span class='mark'>VAO</span>可以理解为一个模型，就好比在<span class='mark'>三维建模软件</span>中，我们需要先创建一个物体然后再进行编辑一样。再比如我们写代码前要先创建一个工程再打开编辑。</p>
<p>目前的<span class='mark'>VAO</span>还是一个空白对象，什么都没有，就类似于一个空白工程。所以我们要给他绑定数据，而绑定数据需要用到<span class='mark'>VBO</span>(Vertex Buffer Object)。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>uint</span> vbo <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.GenBuffers</span><span style='color:rgba(255,255,255,1)'>();</span>             <span style='color:rgba(0,255,0,1)'>// STGL对此函数进行了多个重载</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BindBuffer</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> vbo<span style='color:rgba(255,255,255,1)'>);</span> <span style='color:rgba(0,255,0,1)'>// 将对象绑定到Context中 此buffer用于保存顶点数据</span></pre>
</div>
<p>一个<span class='mark'>VBO</span>可以理解为模型对象的真实数据，类似工程中的代码文件，保存在显存中，所以现在我们要做的就是将数据送入显存。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> vertices<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_STATIC_DRAW</span><span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>将<span class='mark'>vertices</span>送入到当前的<span class='mark'>VBO</span>，并且设置<span class='mark'>GL_STATIC_DRAW</span>标志，表示此数据为静态数据，不会发生变化，<span class='mark'>OpenGL</span>会根据此值决定以何种形式分配显存。可能细心的小伙伴会有疑问为什么这个函数不是下面这个样子的：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferData</span><span style='color:rgba(255,255,255,1)'>(</span>vbo<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> vertices<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_STATIC_DRAW</span><span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>这个需要去了解<span class='mark'>OpenGL</span>的工作机制，<span class='mark'>OpenGL</span>内部是一个超大的状态机，更多的说明可以参考作者的教程，可以理解为内存和显存之间是有数据传送的管道的，而管道上面有插槽，而上面一句<span class='mark'>BindBuffer</span>的代码就是将<span class='mark'>vbo</span>插到插槽上面去。而<span class='mark'>BufferData</span>是直接在往插槽上面送数据。所以在<span class='mark'>OpenGL</span>的原始函数中会看到很多<span class='mark'>glBindXXX</span>之类的函数。</p>
<p>将数据送入显卡之后就完事了吗？不不不。并没有，我们只是送入了一堆数据到显存中去，<span class='mark'>OpenGL</span>并不知道要如何读取这些数据，也就是说，如何结构化这些数据。虽然我们很清楚<span class='mark'>vertices</span>是一个三角形的三个顶点，但是<span class='mark'>OpenGL</span>并不知道。所以我们还要告诉<span class='mark'>OpenGL</span>如何结构化我们刚才送入显存的数据。</p>
<img src='./images/vap.png'/>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.VertexAttribPointer</span><span style='color:rgba(255,255,255,1)'>(</span>         <span style='color:rgba(0,255,0,1)'>// 指定一个数据处理的规则（针对当前绑定的vbo对象）</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span>                          <span style='color:rgba(0,255,0,1)'>// 设定一个通道编号 用于在Shader中进行关联</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>,</span>                          <span style='color:rgba(0,255,0,1)'>// 每一次从vbo中获取3个数据</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_FLOAT</span><span style='color:rgba(255,255,255,1)'>,</span>                <span style='color:rgba(0,255,0,1)'>// 数据类型是float</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>false</span><span style='color:rgba(255,255,255,1)'>,</span>                      <span style='color:rgba(0,255,0,1)'>// 这个参数目前可以不用管 false就行了</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>3</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>),</span>          <span style='color:rgba(0,255,0,1)'>// 下一次获取数据的时候偏移多少数据，也就是每一次取多少字节的数据。</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span>                 <span style='color:rgba(0,255,0,1)'>// 第一次获取数据时候偏移多少 很奇怪这个为什么是IntPtr类型？作者也不知道。</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.EnableVertexAttribArray</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>);</span>  <span style='color:rgba(0,255,0,1)'>// 启用0号通道 下面会做说明</span></pre>
</div>
<p>至此，<span class='mark'>CPU</span>这边的工作基本已经准备完毕了。接下来就是<span class='mark'>GPU</span>层面的准备了，上面说了对于<span class='mark'>OpenGL</span>来说，<span class='mark'>顶点着色器</span>和<span class='mark'>片段着色器</span>是必须的。需要自己编写代码，那么怎么编写代码？</p>
<p><span class='mark'>OpenGL</span>的着色器采用<span class='mark'>GLSL</span>(GL Shader Language)，它是一种<span class='mark'>类C风格</span>的语言。那么我们要如何编写？是不是需要其他<span class='mark'>IDE</span>？？？不不不。。<span class='mark'>OpenGL</span>提供了类似编译器之类的东西。</p>
<p>下面就是<span class='mark'>顶点着色器</span>和<span class='mark'>片段着色器</span>的代码。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>//每一个顶点都会执行一次这个代码 且并行</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>private static</span> <span style='color:rgba(100,149,237,1)'>string</span> m_str_vertex_shader <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(255,165,0,1)'>@"
<span class='span_code_line'></span>#version 330 core                       // 3.3 版本 使用核心模式
<span class='span_code_line'></span>
<span class='span_code_line'></span>layout (location = 0) in vec3 dotPos;   // 还记得上面的0号通道吗？就是和这里做关联的。
<span class='span_code_line'></span>                                        // dotPos就是从0号通道中获取出来的一个3维向量。
<span class='span_code_line'></span>void main(){
<span class='span_code_line'></span>    gl_Position = vec4(dotPos, 1.0);    // 我们先将3维坐标变成4维。
<span class='span_code_line'></span>    // gl_Position是一个内置变量，作为顶点着色器的输出值。也就是预处理后的新顶点。
<span class='span_code_line'></span>    // 除了将三维补成四维之外不做任何处理继续传递 这种用n+1维来表示n维的坐标叫做 齐次坐标
<span class='span_code_line'></span>}"</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>//每一个像素点都会执行一次这个代码 且并行</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>private static</span> <span style='color:rgba(100,149,237,1)'>string</span> m_str_fragment_shader <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(255,165,0,1)'>@"
<span class='span_code_line'></span>#version 330 core
<span class='span_code_line'></span>
<span class='span_code_line'></span>out vec4 fragColor; // 最终需要输出的像素颜色
<span class='span_code_line'></span>
<span class='span_code_line'></span>void main(){
<span class='span_code_line'></span>    fragColor = vec4(1.0, 0.5, 0.2, 1.0); //(RGBA)写死 每个像素点的颜色都将是橙色
<span class='span_code_line'></span>}"</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> gp <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>GLProgram</span><span style='color:rgba(219,112,147,1)'>.Create</span><span style='color:rgba(255,255,255,1)'>(</span>str_vertex_shader<span style='color:rgba(255,255,255,1)'>,</span> str_fragment_shader<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>gp<span style='color:rgba(219,112,147,1)'>.Use</span><span style='color:rgba(255,255,255,1)'>();</span>           <span style='color:rgba(0,255,0,1)'>// 使用当前编译好的着色器 万一有多个可以切换使用</span></pre>
</div>
<p>如果代码没有报错，那么<span class='mark'>gp</span>就是编译好的<span class='mark'>着色器程序</span>。当这一切准备好的时候就可以开始渲染了。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.ClearColor</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>1f</span><span style='color:rgba(255,255,255,1)'>);</span>           <span style='color:rgba(0,255,0,1)'>// 设置背景颜色</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>while</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,0,1)'>/*some code*/</span>) <span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.Clear</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_COLOR_BUFFER_BIT</span><span style='color:rgba(255,255,255,1)'>);</span>       <span style='color:rgba(0,255,0,1)'>// 每次渲染的时候擦除缓存
<span class='span_code_line'></span>    // GL.BindVertexArray(vao);             // 绘制前绑定需要绘制的vao</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.DrawArrays</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_TRIANGLES</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>);</span>   <span style='color:rgba(0,255,0,1)'>// 以三角形方式绘制，一共3个顶点
<span class='span_code_line'></span>    // swapbuffer                           // 交换缓冲器 双缓冲
<span class='span_code_line'></span>    // other code</span>
<span class='span_code_line'></span><span style='color:rgba(255,255,255,1)'>}</span></pre>
</div>
<p>然后就可以看到窗口上的三角形了</p>
<img src='./images/triangle.png'/>
<p>或许你会问假如你想绘制一个四边形是不是传四个顶点进去，然后在结构化<span class='mark'>VBO</span>的时候让他每次取四个数据就好了？然后<span class='mark'>GL.DrawArrays</span>里面的标志换成四边形的？。。不不不。。上面我们仅仅是刚好想绘制一个三角形，而刚好确实也有<span class='mark'>GL_TRIANGLES</span>这个常量值。巧合巧合。。要知道在<span class='mark'>OpenGL</span>中可是一个三维的世界，所以不能用平面绘图的思维去思考问题。如果你想要绘制一个四边形那么你需要两个三角形。什么意思？？？众所周知构成平面的最低要求就是3个顶点，也就是三角形。只要三角形足够多，那么那就可以组合成任意三维模型，比如下面的图：</p>
<img width=755 src='./images/secxun.png'/>
<p>所以上面我们绘制的三角形可能仅仅是某个三维模型的一小块皮，所以<span class='mark'>vertices</span>里面的三角形顶点足够多，那么就可以绘制出任何你想要的形状。比如一个四边形得用下面的数据：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>[]</span> vertices <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第一个顶点</span>
<span class='span_code_line'></span>     <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第二个顶点</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span>  <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第三个顶点</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span>  <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第一个顶点</span>
<span class='span_code_line'></span>     <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,0,1)'>// 第二个顶点</span>
<span class='span_code_line'></span>     <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span>  <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>5f</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0f</span>  <span style='color:rgba(0,255,0,1)'>// 第三个顶点</span>
<span class='span_code_line'></span><span style='color:rgba(255,255,255,1)'>};</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>//======================</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.DrawArrays</span><span style='color:rgba(255,255,255,1)'>(</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_TRIANGLES</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>6</span>                       <span style='color:rgba(0,255,0,1)'>// 一共有6个顶点</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>当然可以看到有两个重复的顶点，这种情况下还会引入<span class='mark'>EBO</span>。不过这里不做介绍。而且真的是一个复杂的模型我们也不可能通过手动构造顶点，而是通过<span class='mark'>建模软件</span>帮我们生成导出，并通过文件加载的形式解析出顶点数据，然后再送入显存。</p>
<div><h2 class='h_option anchor_point' name='a_g'>思路分析</h2></div>
<p>通过两个着色器代码我们可以知道，着色器是并行计算的，至于并发数，我们无需关心，由<span class='mark'>OpenGL</span>或者说显卡自动去分配，着色器代码可以理解为一个函数，每一份数据都会调用它一次。我们的三角形传入的三个顶点会被分成3份数据然后同时调用<span class='mark'>顶点着色器</span>处理，然后结果继续往下传递，然后被<span class='mark'>栅格化</span>成了一堆的像素，然后这些像素也会同时去调用<span class='mark'>片段着色器</span>。而<span class='mark'>GLSL</span>是一个<span class='mark'>类C风格</span>的语言，里面也可以编写函数什么的，那么，我们是否可以在着色器中编写计算<span class='mark'>hash</span>的代码呢？毫无疑问是可以的。只是<span class='mark'>GLSL</span>所支持的数据类型有限不过计算哈希已经足够了。</p>
<p>仔细想一想，刚才的<span class='mark'>vertices</span>中我们传入了3个三角形的顶点，每一份<span class='mark'>顶点着色器</span>会获取到一个顶点。在刚才的<span class='mark'>vertices</span>我们传入的是<span class='mark'>float</span>类型，如果我们使用的是<span class='mark'>uint</span>类型，或者直接就是<span class='mark'>byte</span>类型呢？因为我们在编程的时候所使用的数据类型是什么都无所谓，因为它仅仅是一堆数据被传入到显存中去。刚才上面所看到的<span class='mark'>GL.BufferData</span>其实是<span class='mark'>STGL</span>自己封装出来的一堆重载函数，他所对应的<span class='mark'>OpenGL</span>原生C函数签名如下：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span>void glBufferData(GLenum target, GLsizeiptr size, const void * data, GLenum usage);</span></pre>
</div>
<p>从<span class='mark'>C/C++</span>的角度去思考，其实<span class='mark'>glBufferData</span>就相当于一个内存拷贝的函数，<span class='mark'>void*</span>就可以知道它是无关数据类型的万能指针。真正决定这堆数据如何使用的是<span class='mark'>顶点着色器</span>中的<span class='mark'>layout (location = n) in [TYPE] [NAME]</span>和<span class='mark'>GL.VertexAttribPointer</span>所设定的数据宽度。</p>
<p>所以我们完全可以传入任何我们想传入的数据，通常情况下，一个密码都是<span class='mark'>8-16</span>位，且我们以这个为例，假设密码字符都是<span class='mark'>ASCII</span>字符的情况下。那么16字节足够了。那么我们在使用<span class='mark'>GL.VertexAttribPointer</span>的时候设定成16字节就好了。而且16字节刚好是4个<span class='mark'>uint</span>。那么我们可以这样写代码。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.VertexAttribPointer</span><span style='color:rgba(255,255,255,1)'>(</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span>                  <span style='color:rgba(0,255,0,1)'>// 依然使用0号通道</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>,</span>                  <span style='color:rgba(0,255,0,1)'>// 每次获取4个数据</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_FLOAT</span><span style='color:rgba(255,255,255,1)'>,</span>        <span style='color:rgba(0,255,0,1)'>// 没错这里继续使用FLOAT类型，作者尝试过GL_UNSIGNED_INT了，得不到正确结果。
<span class='span_code_line'></span>                        // 调试发现使用GL_UNSIGNED_INT时候，绑定到uvec4向量的时候采用了FLOAT的内存布局 导致uvec4.xyzw会得到错误值
<span class='span_code_line'></span>                        // 也有可能是我虚拟机中的OpenGL版本问题导致的 可能我的OpenGL不支持uint然后使用缺省(FLOAT)的布局方式
<span class='span_code_line'></span>                        // 这个值并不是告诉OpenGL我们传入的是什么数据类型，而是希望把我们传入的数据当做什么数据类型使用。
<span class='span_code_line'></span>                        // 其实作者也不理解为何顶点着色器中已经指定了通道的数据类型，这里为何还要指定一次。也不太像是历史遗留问题。</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>false</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>4</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>),</span>   <span style='color:rgba(0,255,0,1)'>// 每一份数据的字节宽度，也可以直接写死16 (uint float都是4字节)</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>然后<span class='mark'>顶点着色器</span>中我们从0号通道接收数据的时候使用<span class='mark'>uvec4</span>数据类型：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(255,0,255,1)'>layout</span> <span style='color:rgba(255,255,255,1)'>(</span>location <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>in</span> uvec4 loc_uv4_text<span style='color:rgba(255,255,255,1)'>;</span> <span style='color:rgba(0,255,0,1)'>// 4个uint的四维向量
<span class='span_code_line'></span>// GLSL的数据类型没有那么自由，使用uvecN是最适合的，而且如果是MD5的话 uint也会方便很多
<span class='span_code_line'></span>// uvec4 是一个四维向量分别可以通过 loc_uv4_text.x 获取对应值 一共四个分量(xyzw)每个值是一个uint</span></pre>
</div>
<p>这时候可能你会问，如果密码的字节数超过16位怎么办？没有什么事情是一顿烧烤解决不了的如果有就两顿：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.VertexAttribPointer</span><span style='color:rgba(255,255,255,1)'>(</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span>                  <span style='color:rgba(0,255,0,1)'>// 依然使用0号通道</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_FLOAT</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>false</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>8</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>),</span>   <span style='color:rgba(0,255,0,1)'>// 现在每次获取数据是偏移8个uint了</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.VertexAttribPointer</span><span style='color:rgba(255,255,255,1)'>(</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>,</span>                  <span style='color:rgba(0,255,0,1)'>// 1号通道也用起来</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_FLOAT</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>false</span><span style='color:rgba(255,255,255,1)'>,</span>
<span class='span_code_line'></span>    <span style='color:rgba(144,238,144,1)'>8</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>),</span>   <span style='color:rgba(0,255,0,1)'>// 现在每次获取数据是偏移8个uint了</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>(</span>IntPtr<span style='color:rgba(255,255,255,1)'>)(</span><span style='color:rgba(144,238,144,1)'>4</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>))</span> <span style='color:rgba(0,255,0,1)'>// 第一次获取数据的时候偏移4个uint</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>然后<span class='mark'>顶点着色器</span>中:</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(255,0,255,1)'>layout</span> <span style='color:rgba(255,255,255,1)'>(</span>location <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>in</span> uvec4 loc_uv4_text_1<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span><span style='color:rgba(219,112,147,1)'>layout</span> <span style='color:rgba(255,255,255,1)'>(</span>location <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>in</span> uvec4 loc_uv4_text_2<span style='color:rgba(255,255,255,1)'>;</span></pre>
</div>
<p>用两个<span class='mark'>uvec4</span>作为拼接。当然代价就是浪费显存，因为一个明文需要32字节数据，如果说送入100W个密码到显存中去需要<span class='mark'>30MB</span>内存和显存，如果只用一个<span class='mark'>uvec4</span>那么<span class='mark'>30MB</span>可以送入200W个明文进去计算。因为数据需要结构化，所以哪怕明文只有两个字符，我们也需要字节对齐。我们的案例将采用16字节的明文作为讲解。</p>
<p>那么问题来了我们现在只是可以做到将明文或者说一个字典文件送入显存了。。如果要碰撞<span class='mark'>MD5</span>那么我们是不是还需要一个<span class='mark'>MD5</span>字符串？即便我们可以在着色器编写<span class='mark'>MD5</span>的算法，那么每计算一次总的需要一个<span class='mark'>MD5</span>去判断吧？如果判断一毛一样了，说明碰撞成功了，那么我们还得知道是哪个明文碰撞出来的吧？。。这个要怎么搞？</p>
<p><span class='mark'>MD5</span>字符串我们也是通过<span class='mark'>vertices</span>传入进去吗？。。。不不不。。。在着色器代码中有一个数据类型<span class='mark'>uniform</span>被<span class='mark'>uniform</span>修饰的变量可以和<span class='mark'>CPU</span>交互，也就是说可以在<span class='mark'>CPU</span>端的代码对其进行设置或者读取。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(255,0,255,1)'>layout</span> <span style='color:rgba(255,255,255,1)'>(</span>location <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>in</span> uvec4 loc_uv4_text<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>//用于保存最终结果</span>
<span class='span_code_line'></span>varying <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>]</span> m_result<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>//用于保存MD5密文</span>
<span class='span_code_line'></span>uniform <span style='color:rgba(100,149,237,1)'>uint</span> u_x<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>uniform <span style='color:rgba(100,149,237,1)'>uint</span> u_y<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>uniform <span style='color:rgba(100,149,237,1)'>uint</span> u_z<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>uniform <span style='color:rgba(100,149,237,1)'>uint</span> u_w<span style='color:rgba(255,255,255,1)'>;</span></pre>
</div>
<p>如上，我们用4个<span class='mark'>uint</span>来保存密文，4个uint刚好16字节。但是可以看到，作者用了一个<span class='mark'>varying</span>修饰的<span class='mark'>m_result</span>来保存结果，也就是说哪个明文计算结果与目标密文一直。或许你又不理解了，<span class='mark'>uniform</span>可以被<span class='mark'>CPU</span>读取和设置，为什么我们还要用一个<span class='mark'>verying</span>修饰的<span class='mark'>float</span>数组来保存结果？直接再用一个<span class='mark'>uniform</span>来保存结果就好了啊。是的想法没错，但是要知道被<span class='mark'>uniform</span>所修饰的数据类型对于着色器代码来说他是只读不可写。所以凉凉。。。而<span class='mark'>varying</span>是可读写，但无法和<span class='mark'>CPU</span>进行交互。且支持数据类型有限，无法使用整数型。所以我们用了16个<span class='mark'>float</span>当做16个<span class='mark'>byte</span>用。</p>
<p>不对啊。。不是说不能和<span class='mark'>CPU</span>交互吗？那我们要怎么获取计算结果啊。。。是的。。这很烦。。毕竟这是<span class='mark'>图形渲染管线</span>中。而不是在类似于<span class='mark'>CUDA</span>或者<span class='mark'>OpenCL</span>在通用计算单元中。。。<span class='mark'>图形渲染管线</span>是用来渲染实3D图像的。只是我们在用<span class='mark'>图形渲染管线</span>干着非主流的事情。起码以目前作者的知识还并不知道要怎么样从着色器中直接返回一个数据给<span class='mark'>CPU</span>。但是也并不是说没有办法。那我们就按<span class='mark'>图形渲染管线</span>的规则来。他最终会渲染一帧图像来是吧？图像是不是有像素？像素是不是<span class='mark'>RGB</span>?好的。问题解决了。我们将结果写入渲染的图像中。然后获取像素值。这样一来整个流程就通了。</p>
<div class='div_hightlight' style='background-color:pink;color:black'>
<p><span class='mark'>uniform</span>和<span class='mark'>varying</span>在同一个<span class='mark'>GLProgram</span>中为全局变量。当然需要在不同的着色器中声明同样的变量，它们将会自动关联在一起。</p>
</div>
<p>所以我们直接在<span class='mark'>顶点着色器</span>中算<span class='mark'>MD5</span>，<span class='mark'>片段着色器</span>中写入结果。就这么愉快的决定了。</p>
<p>那么除了<span class='mark'>vertices</span>我们通过<span class='mark'>BufferData</span>送入显存，那么上面的四个<span class='mark'>uniform</span>要怎么处理？</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 着色器代码有点多，我们直接从外部加载</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> str_vertex_shader <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>System</span><span style='color:rgba(112,128,144,1)'>.IO.File</span><span style='color:rgba(219,112,147,1)'>.ReadAllText</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"./glsl_md5.vs"</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> str_fragment_shader <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>System</span><span style='color:rgba(112,128,144,1)'>.IO.File</span><span style='color:rgba(219,112,147,1)'>.ReadAllText</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"./glsl_md5.fs"</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> gp <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>GLProgram</span><span style='color:rgba(219,112,147,1)'>.Create</span><span style='color:rgba(255,255,255,1)'>(</span>str_vertex_shader<span style='color:rgba(255,255,255,1)'>,</span> str_fragment_shader<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>gp<span style='color:rgba(219,112,147,1)'>.Use</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// strTargetMd5为目标Md5字符串</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[]</span> arrs_result <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>OpenGLMd5</span><span style='color:rgba(219,112,147,1)'>.Md5ToUints</span><span style='color:rgba(255,255,255,1)'>(</span>strTargetMd5<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>gp<span style='color:rgba(219,112,147,1)'>.SetUniform</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"u_x"</span><span style='color:rgba(255,255,255,1)'>,</span> arrs_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]);</span>
<span class='span_code_line'></span>gp<span style='color:rgba(219,112,147,1)'>.SetUniform</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"u_y"</span><span style='color:rgba(255,255,255,1)'>,</span> arrs_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>]);</span>
<span class='span_code_line'></span>gp<span style='color:rgba(219,112,147,1)'>.SetUniform</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"u_z"</span><span style='color:rgba(255,255,255,1)'>,</span> arrs_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>]);</span>
<span class='span_code_line'></span>gp<span style='color:rgba(219,112,147,1)'>.SetUniform</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"u_w"</span><span style='color:rgba(255,255,255,1)'>,</span> arrs_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>]);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 至于怎么将Md5字符串转换成四个uint大家可以各显神通，下面并不是最好的办法，仅仅是方便，反正只执行一次。</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>public static</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[]</span> <span style='color:rgba(255,0,255,1)'>Md5ToUints</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>string</span> strMd5<span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[]</span> ret <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>];</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>[]</span> by_md5 <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>];</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>for</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>int</span> i <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span> i <span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>;</span> i<span style='color:rgba(255,255,255,1)'>++</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>        by_md5<span style='color:rgba(255,255,255,1)'>[</span>i<span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>Convert</span><span style='color:rgba(219,112,147,1)'>.ToByte</span><span style='color:rgba(255,255,255,1)'>(</span>strMd5<span style='color:rgba(219,112,147,1)'>.Substring</span><span style='color:rgba(255,255,255,1)'>(</span>i <span style='color:rgba(255,255,255,1)'>&lt;</span><span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>),</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>unsafe</span> <span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>fixed</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>void</span><span style='color:rgba(255,255,255,1)'>*</span> ptr_src <span style='color:rgba(255,255,255,1)'>= &</span>amp<span style='color:rgba(255,255,255,1)'>;</span>by_md5<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>])</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>fixed</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>void</span><span style='color:rgba(255,255,255,1)'>*</span> ptr_dst <span style='color:rgba(255,255,255,1)'>= &</span>amp<span style='color:rgba(255,255,255,1)'>;</span>ret<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]) {</span>
<span class='span_code_line'></span>            <span style='color:rgba(0,255,255,1)'>Pointer</span><span style='color:rgba(219,112,147,1)'>.Copy</span><span style='color:rgba(255,255,255,1)'>(</span>ptr_dst<span style='color:rgba(255,255,255,1)'>,</span> ptr_src<span style='color:rgba(255,255,255,1)'>,</span> by_md5<span style='color:rgba(112,128,144,1)'>.Length</span> <span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>16</span> <span style='color:rgba(255,255,255,1)'>?</span> by_md5<span style='color:rgba(112,128,144,1)'>.Length</span> <span style='color:rgba(255,255,255,1)'>:</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>        }
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>return</span> ret<span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>}</span></pre>
</div>
<div><h2 class='h_option anchor_point' name='a_h'>MD5算法</h2></div>
<p>MD5: <a class='mark' target='_blank' href='https://www.rfc-editor.org/rfc/rfc1321'>RFC-1321</a></p>
<p>网上找一找能找到一大堆的<span class='mark'>MD5</span>算法，唯一不同的是，这个算法我们需要使用<span class='mark'>GLSL</span>编写。<span class='mark'>MD5</span>有两个重要步骤，一个是字节补齐，一个是计算。</p>
<p><span class='mark'>MD5</span>计算是需要的数据长度必须是<span class='mark'>512</span>的整数倍的<span class='mark'>bit</span>位，也就是说64字节的倍数。并且最后16字节是原始数据的长度。如果参与计算的数据总长度无法是整数倍则补齐到整数倍。也就是说差不多是下面的结构</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span>[原始数据|填充数据|原始数据长度(16字节)].Length % 64 = 0</span></pre>
</div>
<div class='div_hightlight' style='background-color:pink;color:black'>
<p>注意：最后部分的原始数据长度是<span class='mark'>bit</span>位，不是字节长度。关于国内一些文档的翻译并没有提到这一点。</p>
</div>
<p>而填充数据的规则为[0x80,0,0,...]，也就是说从二进制的角度去看在原始数据后面补一个<span class='mark'>1</span>然后一直填充<span class='mark'>0</span>直到满足上面的规则。</p>
<p>我们的密码才多少字节？16字节。。别说16字节，就算32字节。的密码也在64字节的范围内。所以关于字节补齐的这个步骤我们可以直接写死以加快算法速度，我们肯定是返回64字节的。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// GLSL 顶点着色器中的代码片段
<span class='span_code_line'></span>// 16个uint刚好就是64字节，所以代码直接写死。</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(219,112,147,1)'>MD5_Append</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>uvec4</span> uv4<span style='color:rgba(255,255,255,1)'>){</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,0,1)'>// uv4为0号通道获取到的数据
<span class='span_code_line'></span>    // 所以uv4是我们的明文数据，我们需要检测明文数据长度，看看那个字节是0</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>uint</span> z <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>((</span>uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x000000FF</span><span style='color:rgba(255,255,255,1)'>))</span> <span style='color:rgba(255,255,255,1)'>==</span> z<span style='color:rgba(255,255,255,1)'>) {</span> <span style='color:rgba(0,255,0,1)'>// 0字节</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>return</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>] (</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x00000080</span><span style='color:rgba(255,255,255,1)'>),</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z <span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>((</span>uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x0000FF00</span><span style='color:rgba(255,255,255,1)'>))</span> <span style='color:rgba(255,255,255,1)'>==</span> z<span style='color:rgba(255,255,255,1)'>) {</span> <span style='color:rgba(0,255,0,1)'>// 1字节 后面的uint(8)表原始数据8个bit位</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>return</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>] (</span> uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x000000FF</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>|</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x00008000</span><span style='color:rgba(255,255,255,1)'>),</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>8</span><span style='color:rgba(255,255,255,1)'>),</span> z <span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,0,1)'>// ....</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>return</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>] (</span> uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>],</span> uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>],</span> uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>],</span> uv4<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>],</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> z<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>128</span><span style='color:rgba(255,255,255,1)'>),</span> z <span style='color:rgba(255,255,255,1)'>);</span> <span style='color:rgba(0,255,0,1)'>// 16字节的明文</span>
<span class='span_code_line'></span><span style='color:rgba(255,255,255,1)'>}</span></pre>
</div>
<p>然后就是计算<span class='mark'>MD5</span>的过程，这个过程就不贴代码了，毕竟没有太多特别的地方。同样的，计算的中循环我们也可以去掉，我们的算法只会执行一次流程没必要使用循环。</p>
<div><h2 class='h_option anchor_point' name='a_i'>计算过程</h2></div>
<p>然后就是<span class='mark'>顶点着色器</span>的<span class='mark'>main</span>函数。也就是入口。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>void</span> <span style='color:rgba(255,0,255,1)'>main</span><span style='color:rgba(255,255,255,1)'>(){</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,0,1)'>// gl_XXXX开头的都是GLSL内置变量 我不会以三角形方式渲染图像，而是直接绘制顶点
<span class='span_code_line'></span>    // 不然使用三角形 鬼知道我们传入的数据会组合成什么样的三角形 而且还会执行栅格化</span>
<span class='span_code_line'></span>    gl_PointSize <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>1000</span><span style='color:rgba(255,255,255,1)'>;</span> <span style='color:rgba(0,255,0,1)'>//设置顶点大小，其实我们只需要6个像素就够了6 * RGB = 18字节了</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>uint</span> arr<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>MD5_Append</span><span style='color:rgba(255,255,255,1)'>(</span>loc_uv4_text<span style='color:rgba(255,255,255,1)'>);</span>    <span style='color:rgba(0,255,0,1)'>// 字节补齐</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>uint</span> md5<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>MD5_Trasform</span><span style='color:rgba(255,255,255,1)'>(</span>arr<span style='color:rgba(255,255,255,1)'>);</span>            <span style='color:rgba(0,255,0,1)'>// 计算md5
<span class='span_code_line'></span>    // loc_uv4_text是当前着色器从0号通道获取到的数据，如果计算出来的结果和uniform变量一直
<span class='span_code_line'></span>    // 那么我们就将这个明文保存到m_result中并在片段着色器中作为像素值输出</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span><span style='color:rgba(255,255,255,1)'>(</span>md5<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>==</span> u_x <span style='color:rgba(255,255,255,1)'>&amp;</span><span style='color:rgba(255,255,255,1)'>&amp;</span> md5<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>==</span> u_y <span style='color:rgba(255,255,255,1)'>&amp;</span><span style='color:rgba(255,255,255,1)'>&amp;</span> md5<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>==</span> u_z <span style='color:rgba(255,255,255,1)'>&amp;</span><span style='color:rgba(255,255,255,1)'>&amp;</span> md5<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>==</span> u_w<span style='color:rgba(255,255,255,1)'>){</span>
<span class='span_code_line'></span>        m_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>((</span>loc_uv4_text<span style='color:rgba(112,128,144,1)'>.x</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x000000FF</span><span style='color:rgba(255,255,255,1)'>));</span>
<span class='span_code_line'></span>        m_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>((</span>loc_uv4_text<span style='color:rgba(112,128,144,1)'>.x</span> <span style='color:rgba(255,255,255,1)'>&gt;</span><span style='color:rgba(255,255,255,1)'>&gt;</span> <span style='color:rgba(144,238,144,1)'>8</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x000000FF</span><span style='color:rgba(255,255,255,1)'>));</span>
<span class='span_code_line'></span>        m_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>((</span>loc_uv4_text<span style='color:rgba(112,128,144,1)'>.x</span> <span style='color:rgba(255,255,255,1)'>&gt;</span><span style='color:rgba(255,255,255,1)'>&gt;</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x000000FF</span><span style='color:rgba(255,255,255,1)'>));</span>
<span class='span_code_line'></span>        m_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>(</span>loc_uv4_text<span style='color:rgba(112,128,144,1)'>.x</span> <span style='color:rgba(255,255,255,1)'>&gt;</span><span style='color:rgba(255,255,255,1)'>&gt;</span> <span style='color:rgba(144,238,144,1)'>24</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span>        m_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>((</span>loc_uv4_text<span style='color:rgba(112,128,144,1)'>.y</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>&amp;</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0x000000FF</span><span style='color:rgba(255,255,255,1)'>));</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,0,1)'>// ...</span>
<span class='span_code_line'></span>        gl_Position <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>vec4</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>);</span> <span style='color:rgba(0,255,0,1)'>// 此坐标在OpenGL归一化空间Z方向投影的左下角</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>}</span><span style='color:rgba(30,144,255,1)'>else</span><span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,0,1)'>// 此坐标在归一化空间之外会被栅格化裁剪并丢弃 所以不会有像素参数 片段着色器不会触发</span>
<span class='span_code_line'></span>        gl_Position <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>vec4</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(255,255,255,1)'>-</span><span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span></pre>
</div>
<p><span class='mark'>OpenGL</span>使用一个<span class='mark'>2*2*2</span>的立方体作为归一化空间，立方体中心是原点坐标。而这个立方体的正面则与显示视窗对应，而最终视窗显示画面就是z平面的空间投影。这里不做过多介绍了。反正在这个立方体之外的坐标都会被裁剪掉。因为没有计算出正确结果前，我们没必要让<span class='mark'>片段着色器</span>运行。一旦<span class='mark'>片段着色器</span>被触发那就说明计算出了正确的结果了。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span>#version <span style='color:rgba(144,238,144,1)'>330</span> core
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 片段着色器全部代码
<span class='span_code_line'></span>// 此变量与顶点着色器中的同名变量关联 即:结果</span>
<span class='span_code_line'></span>varying <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>]</span> m_result<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>out</span> vec4 fragColor<span style='color:rgba(255,255,255,1)'>;</span> <span style='color:rgba(0,255,0,1)'>//当前像素需要输出的颜色</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>void</span> <span style='color:rgba(255,0,255,1)'>main</span><span style='color:rgba(255,255,255,1)'>(){</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,0,1)'>// 我们在顶点着色器中输出的坐标为(-1,-1,0,1)。即在二维平面的左下角
<span class='span_code_line'></span>    // gl_FragCoord 当前着色器输出的颜色位于显示视窗中的那个像素
<span class='span_code_line'></span>    // 最终屏幕中的像素是以RGB呈现 所以我们需要6个像素来写入结果
<span class='span_code_line'></span>    // 6 * 3 = 18 m_result有16个值</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>int</span> x <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>int</span><span style='color:rgba(255,255,255,1)'>(</span>gl_FragCoord<span style='color:rgba(112,128,144,1)'>.x</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span><span style='color:rgba(255,255,255,1)'>(</span>x <span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>15</span><span style='color:rgba(255,255,255,1)'>){</span>     <span style='color:rgba(0,255,0,1)'>// 15 = 5 * 3, 也就是前面5个像素</span>
<span class='span_code_line'></span>        fragColor <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>vec4</span><span style='color:rgba(255,255,255,1)'>(</span>
<span class='span_code_line'></span>            m_result<span style='color:rgba(255,255,255,1)'>[</span>x<span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>255</span><span style='color:rgba(255,255,255,1)'>),</span>       <span style='color:rgba(0,255,0,1)'>// R</span>
<span class='span_code_line'></span>            m_result<span style='color:rgba(255,255,255,1)'>[</span>x <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>255</span><span style='color:rgba(255,255,255,1)'>),</span>   <span style='color:rgba(0,255,0,1)'>// G</span>
<span class='span_code_line'></span>            m_result<span style='color:rgba(255,255,255,1)'>[</span>x <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>255</span><span style='color:rgba(255,255,255,1)'>),</span>   <span style='color:rgba(0,255,0,1)'>// B</span>
<span class='span_code_line'></span>            <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(112,128,144,1)'>.</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>);</span>                           <span style='color:rgba(0,255,0,1)'>// A</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>}</span><span style='color:rgba(30,144,255,1)'>else if</span><span style='color:rgba(255,255,255,1)'>(</span>x <span style='color:rgba(255,255,255,1)'>==</span> <span style='color:rgba(144,238,144,1)'>15</span><span style='color:rgba(255,255,255,1)'>){</span>
<span class='span_code_line'></span>        fragColor <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>vec4</span><span style='color:rgba(255,255,255,1)'>(</span>m_result<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>15</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(100,149,237,1)'>float</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>255</span><span style='color:rgba(255,255,255,1)'>),</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }</span><span style='color:rgba(30,144,255,1)'>else</span><span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>        fragColor <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(219,112,147,1)'>vec4</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>,</span><span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>);</span>          <span style='color:rgba(0,255,0,1)'>// 其他区域随便给个颜色比如蓝色</span>
<span class='span_code_line'></span>    <span style='color:rgba(255,255,255,1)'>}
<span class='span_code_line'></span>}</span></pre>
</div>
<div><h2 class='h_option anchor_point' name='a_j'>批量计算</h2></div>
<p>接下来就是将字典分批送入显存中。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// nCountForFrame表示没渲染一帧画面 准备送入多少个密码明文到显存</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[]</span> u_arrs_text_buffer <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[</span>nCountForFrame <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(144,238,144,1)'>4</span><span style='color:rgba(255,255,255,1)'>];</span> <span style='color:rgba(0,255,0,1)'>//最终要送入显存的数据</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>int</span> nBufferLen <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>*</span> u_arrs_text_buffer<span style='color:rgba(112,128,144,1)'>.Length</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>uint</span> vbo <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.GenBuffers</span><span style='color:rgba(255,255,255,1)'>();</span>         <span style='color:rgba(0,255,0,1)'>// 创建一个buffer对象并得到id STGL对此函数进行了多个重载</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BindBuffer</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> vbo<span style='color:rgba(255,255,255,1)'>);</span> <span style='color:rgba(0,255,0,1)'>// 将对象绑定到Context中 此buffer用于保存顶点数据</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> nBufferLen<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_STREAM_DRAW_ARB</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>//GL_STREAM_DRAW_ARB 表示数据是一直在变化的 每一帧数据都会变化
<span class='span_code_line'></span>//当时上面的代码并没有拷贝数据，我们将打算使用GL.BufferSubData进行数据拷贝。</span></pre>
</div>
<p>加载字典</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>using</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>StreamReader</span> reader <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(0,255,255,1)'>StreamReader</span><span style='color:rgba(255,255,255,1)'>(</span>strDic<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(255,255,255,1)'>)) {</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>int</span> nCounter <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>string</span> strLine <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>string</span><span style='color:rgba(112,128,144,1)'>.Empty</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>while</span> <span style='color:rgba(255,255,255,1)'>((</span>strLine <span style='color:rgba(255,255,255,1)'>=</span> reader<span style='color:rgba(219,112,147,1)'>.ReadLine</span><span style='color:rgba(255,255,255,1)'>())</span> <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(30,144,255,1)'>null</span><span style='color:rgba(255,255,255,1)'>) {</span> <span style='color:rgba(0,255,0,1)'>// 每读取一行写入到vbo需要的buffer中</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>OpenGLMd5</span><span style='color:rgba(219,112,147,1)'>.TextToBuffer</span><span style='color:rgba(255,255,255,1)'>(</span>u_arrs_text_buffer<span style='color:rgba(255,255,255,1)'>,</span> nCounter <span style='color:rgba(255,255,255,1)'>&lt;</span><span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>,</span> strLine<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,255,255,1)'>++</span>nCounter <span style='color:rgba(255,255,255,1)'>!=</span> nCountForFrame<span style='color:rgba(255,255,255,1)'>) {</span>         <span style='color:rgba(0,255,0,1)'>// 到达设定的条数</span>
<span class='span_code_line'></span>            <span style='color:rgba(30,144,255,1)'>continue</span><span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>        }</span>   <span style='color:rgba(0,255,0,1)'>// 然后将数据拷贝至显存</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferSubData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span><span style='color:rgba(255,255,255,1)'>,</span> u_arrs_text_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.DrawArrays</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_POINTS</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> nCounter<span style='color:rgba(255,255,255,1)'>);</span>   <span style='color:rgba(0,255,0,1)'>// 这里我们直接渲染顶点而不是三角形</span>
<span class='span_code_line'></span>        nCounter <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>                               <span style='color:rgba(0,255,0,1)'>// 计数清0</span>
<span class='span_code_line'></span>        strResult <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>OpenGLMd5</span><span style='color:rgba(219,112,147,1)'>.GetResult</span><span style='color:rgba(255,255,255,1)'>(</span>b_arrs_result_buffer<span style='color:rgba(255,255,255,1)'>);</span> <span style='color:rgba(0,255,0,1)'>// 每渲染一帧 获取一下像素</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>strResult <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(30,144,255,1)'>null</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>return</span> strResult<span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>nCounter <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>) {</span> <span style='color:rgba(0,255,0,1)'>// 将剩下的数据送入显存</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferSubData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span><span style='color:rgba(255,255,255,1)'>,</span> nCounter <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(144,238,144,1)'>4</span> <span style='color:rgba(255,255,255,1)'>*</span> <span style='color:rgba(100,149,237,1)'>sizeof</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>),</span> u_arrs_text_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.DrawArrays</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_POINTS</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> nCounter<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        strResult <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>OpenGLMd5</span><span style='color:rgba(219,112,147,1)'>.GetResult</span><span style='color:rgba(255,255,255,1)'>(</span>b_arrs_result_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>strResult <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(30,144,255,1)'>null</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>return</span> strResult<span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 同理如何把 strText 写入 buffers 中大家可以各显神通，同样的这不是最好的方法，仅仅是方便。</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>public static</span> <span style='color:rgba(100,149,237,1)'>void</span> <span style='color:rgba(255,0,255,1)'>TextToBuffer</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>uint</span><span style='color:rgba(255,255,255,1)'>[]</span> buffers<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(100,149,237,1)'>int</span> nIndex<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(100,149,237,1)'>string</span> strText<span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>    buffers<span style='color:rgba(255,255,255,1)'>[</span>nIndex<span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>        <span style='color:rgba(0,255,0,1)'>// 每个明文数据我们给定16字节 先将数据全部清0</span>
<span class='span_code_line'></span>    buffers<span style='color:rgba(255,255,255,1)'>[</span>nIndex <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>    <span style='color:rgba(0,255,0,1)'>// 在顶点着色器中将通过判断0来确认数据长度</span>
<span class='span_code_line'></span>    buffers<span style='color:rgba(255,255,255,1)'>[</span>nIndex <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(144,238,144,1)'>2</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    buffers<span style='color:rgba(255,255,255,1)'>[</span>nIndex <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(144,238,144,1)'>3</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>[]</span> byText <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(219,112,147,1)'>.GetBytes</span><span style='color:rgba(255,255,255,1)'>(</span>strText<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>unsafe</span> <span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>fixed</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>void</span><span style='color:rgba(255,255,255,1)'>*</span> ptr_src <span style='color:rgba(255,255,255,1)'>= &</span>amp<span style='color:rgba(255,255,255,1)'>;</span>byText<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>])</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>fixed</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>void</span><span style='color:rgba(255,255,255,1)'>*</span> ptr_dst <span style='color:rgba(255,255,255,1)'>= &</span>amp<span style='color:rgba(255,255,255,1)'>;</span>buffers<span style='color:rgba(255,255,255,1)'>[</span>nIndex<span style='color:rgba(255,255,255,1)'>]) {</span>
<span class='span_code_line'></span>            <span style='color:rgba(0,255,255,1)'>Pointer</span><span style='color:rgba(219,112,147,1)'>.Copy</span><span style='color:rgba(255,255,255,1)'>(</span>ptr_dst<span style='color:rgba(255,255,255,1)'>,</span> ptr_src<span style='color:rgba(255,255,255,1)'>,</span> byText<span style='color:rgba(112,128,144,1)'>.Length</span> <span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>16</span> <span style='color:rgba(255,255,255,1)'>?</span> byText<span style='color:rgba(112,128,144,1)'>.Length</span> <span style='color:rgba(255,255,255,1)'>:</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>        }
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 每渲染一帧读取一下像素。glReadPixels的原点坐标在左下角，读取6个像素就好了</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>private static</span> <span style='color:rgba(100,149,237,1)'>string</span> <span style='color:rgba(255,0,255,1)'>GetResult</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>[]</span> byBuffer<span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>unsafe</span> <span style='color:rgba(255,255,255,1)'>{</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>fixed</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>*</span> ptr <span style='color:rgba(255,255,255,1)'>= &</span>amp<span style='color:rgba(255,255,255,1)'>;</span>byBuffer<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]) {</span>
<span class='span_code_line'></span>            <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.ReadPixels</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>6</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>1</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_RGB</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_UNSIGNED_BYTE</span><span style='color:rgba(255,255,255,1)'>, (</span><span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(255,255,255,1)'>)</span>ptr<span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>        }
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>byBuffer<span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>) {</span> <span style='color:rgba(0,255,0,1)'>// 如果左下角有像素被设定，那说明触发片段着色器了。有结果了。</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>return</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(219,112,147,1)'>.GetString</span><span style='color:rgba(255,255,255,1)'>(</span>byBuffer<span style='color:rgba(255,255,255,1)'>)</span><span style='color:rgba(219,112,147,1)'>.Trim</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>'\0'</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>return null</span><span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>}</span></pre>
</div>
<p>好了大功告成了。。。关键代码已经全部完成。。下面就是开始封装进行试验。</p>
<div><h2 class='h_option anchor_point' name='a_k'>试验效果</h2></div>
<p>为了检验效果差距，我们需要编写一个<span class='mark'>CPU</span>方式计算的作为对比，<span class='mark'>CPU</span>计算的方式这里就不贴代码了。然后我们生成<span class='mark'>1000W</span>个字典，并将最后一个作为结果</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>using</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>StreamWriter</span> writer <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(0,255,255,1)'>StreamWriter</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"./md5_test.txt"</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(30,144,255,1)'>false</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(255,255,255,1)'>)) {</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>for</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>int</span> i <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span> i <span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>10000000</span><span style='color:rgba(255,255,255,1)'>;</span> i<span style='color:rgba(255,255,255,1)'>++</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>        writer<span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span>i<span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 最后一个是 9999999 MD5: 283f42764da6dba2522412916b031080
<span class='span_code_line'></span>// other code
<span class='span_code_line'></span>// ...</span>
<span class='span_code_line'></span>sw<span style='color:rgba(219,112,147,1)'>.Start</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> aa <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>CPUMd5</span><span style='color:rgba(219,112,147,1)'>.Run</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"./md5_test.txt"</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,165,0,1)'>"283f42764da6dba2522412916b031080"</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>sw<span style='color:rgba(219,112,147,1)'>.Stop</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>Console</span><span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"CPU_TIME: "</span> <span style='color:rgba(255,255,255,1)'>+</span> sw<span style='color:rgba(112,128,144,1)'>.ElapsedMilliseconds</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>Console</span><span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"CPU_RESULT: "</span> <span style='color:rgba(255,255,255,1)'>+</span> aa<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>Console</span><span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"====================================="</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>sw<span style='color:rgba(219,112,147,1)'>.Reset</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span>sw<span style='color:rgba(219,112,147,1)'>.Start</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// 每次送入400W个明文到显存</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> bb <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>OpenGLMd5</span><span style='color:rgba(219,112,147,1)'>.Run</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"./md5_test.txt"</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(255,165,0,1)'>"283f42764da6dba2522412916b031080"</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>4000000</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>sw<span style='color:rgba(219,112,147,1)'>.Stop</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>Console</span><span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"GL_TIME: "</span> <span style='color:rgba(255,255,255,1)'>+</span> sw<span style='color:rgba(112,128,144,1)'>.ElapsedMilliseconds</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>Console</span><span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"GL_RESULT: "</span> <span style='color:rgba(255,255,255,1)'>+</span> bb<span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>效果如下：</p>
<img src='./images/result.png'/>
<p>额。。。。好像效果也不是很理想啊。。虽然确实比<span class='mark'>CPU</span>快了很多。。。但是根本没有预期的那么好啊。。没事问题不大。。毕竟一个<span class='mark'>Demo</span>已经先出来了。。这个时候去和<span class='mark'>Hashcat</span>对比看看差距到底有多大。。然后将工程拷贝到<span class='mark'>Linux</span>环境下并且用<span class='mark'>dotnet</span>进行编译。</p>
<img width=690 src='./images/linux_gl.png'/>
<p>好家伙。。看来我的古董<span class='mark'>Server2008</span>虚拟机是时候换掉了。。。然后再来看看<span class='mark'>Hashcat</span>。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span>hashcat -a 0 -m 0 283f42764da6dba2522412916b031080 ./md5_test.txt -O</span></pre>
</div>
<p>听说加上<span class='mark'>-O</span>有<span class='mark'>Buff</span>加成。。反正它的提示是这么告诉我的。。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span>You can use it in your cracking session by setting the -O option.
<span class='span_code_line'></span>Note: Using optimized kernel code limits the maximum supported password length.</span></pre>
</div>
<img width=683 src='./images/linux_hashcat.png'/>
<p>😶😶😶😶😶....如果我没有算错的话。。。是不是<span class='mark'>49S</span>？？？？人都看傻了 。。。。以为打开方式不对加不加<span class='mark'>-O</span>效果差不了多少。。于是运行它的基准测试</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span>hashcat -b -m 0</span></pre>
</div>
<img width=683 src='./images/linux_hashcat_bm.png'/>
<p>可以看到速度<span class='mark'>87918KH/s</span>如果我没有理解错误的话是不是每一秒可以计算<span class='mark'>8791.8W</span>次？？？那么为何差距会这么悬殊？即便在没有使用硬件加速的情况下。。<span class='mark'>49S</span>的速度连<span class='mark'>.Net</span>的<span class='mark'>CPU</span>代码都没跑过。。这说不过去啊。。到这里作者已经不想纠结是什么原因造成的了。。而是在想如果真的可以差不多每秒<span class='mark'>8791.8W</span>此，那岂不是作者被按在地上踩？？？？而且那么这<span class='mark'>1000W</span>的字典岂不是可以瞬间跑完？？？老实说<span class='mark'>hashcat</span>的源码也不怎么想去看，能力不足，看着头疼。不过大概猜到了原因。跑基准测试的时候，统计的是计算能力。所以也不存在什么说要不停结构化数据然后送入显存，跑跑死数据就能统计出计算能力。然后改改代码试试：</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>long</span> nFrameCounter <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> nPwdCount <span style='color:rgba(255,255,255,1)'>=</span> by_buffer<span style='color:rgba(112,128,144,1)'>.Length</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>var</span> sw <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> System<span style='color:rgba(112,128,144,1)'>.Diagnostics</span><span style='color:rgba(0,255,255,1)'>.Stopwatch</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span>sw<span style='color:rgba(219,112,147,1)'>.Start</span><span style='color:rgba(255,255,255,1)'>();</span>
<span class='span_code_line'></span><span style='color:rgba(100,149,237,1)'>long</span> l_time <span style='color:rgba(255,255,255,1)'>=</span> sw<span style='color:rgba(112,128,144,1)'>.ElapsedMilliseconds</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>while</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(30,144,255,1)'>true</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>    nFrameCounter<span style='color:rgba(255,255,255,1)'>++</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,0,1)'>// 虽然是重复数据 每一帧还是重新拷贝一次到显存吧</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferSubData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span><span style='color:rgba(255,255,255,1)'>,</span> by_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>    <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.DrawArrays</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_POINTS</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>, (</span><span style='color:rgba(100,149,237,1)'>int</span><span style='color:rgba(255,255,255,1)'>)</span>nPwdCount<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>    strResult <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>OpenGLMd5_1</span><span style='color:rgba(219,112,147,1)'>.GetResult</span><span style='color:rgba(255,255,255,1)'>(</span>b_arrs_result_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>strResult <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(30,144,255,1)'>null</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>return</span> strResult<span style='color:rgba(255,255,255,1)'>;</span> <span style='color:rgba(0,255,0,1)'>// 当然不会有正确结果出来</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>long</span> l_temp <span style='color:rgba(255,255,255,1)'>=</span> sw<span style='color:rgba(112,128,144,1)'>.ElapsedMilliseconds</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>l_temp <span style='color:rgba(255,255,255,1)'>-</span> l_time <span style='color:rgba(255,255,255,1)'>&gt;</span><span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>1000</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>        l_time <span style='color:rgba(255,255,255,1)'>=</span> l_temp<span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>Console</span><span style='color:rgba(219,112,147,1)'>.WriteLine</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"AVG_SPEED: "</span> <span style='color:rgba(255,255,255,1)'>+</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>long</span><span style='color:rgba(255,255,255,1)'>)((</span>nFrameCounter <span style='color:rgba(255,255,255,1)'>*</span> nPwdCount<span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(255,255,255,1)'>(</span>sw<span style='color:rgba(112,128,144,1)'>.ElapsedMilliseconds</span> <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(144,238,144,1)'>1000f</span><span style='color:rgba(255,255,255,1)'>)));
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span></pre>
</div>
<img src='./images/speed.png'/>
<p>好家伙，平均1.2亿次计算。。。如果将拷贝数据至显存的代码注释能达到9亿。作者每一帧传入的是<span class='mark'>400W</span>个密码。所以到这里大伙们也知道应该从哪里优化代码了吧？很多时间被加载字典和送入显存给耽误了，纯计算的速度是很逆天的。所以要优化的话应该直接从文件加载去入手。</p>
<div><h2 class='h_option anchor_point' name='a_l'>优化方案</h2></div>
<p>不管怎么说，上面的速度确实很快，但是实际上是并不符合实际应用的。实际应用中我们也不可能跑死数据的。<span style='color:pink'>而且对于<span class='mark'>Hashcat</span>的基准测试作者也仅仅是猜测跑是数据，并没有实际的证据。</span>上面的毕竟是理论，无法实战。所以我们看看依然使用我们生成的那个字典，能否再次提高一下速度？这里我们并不讨论如何加快读取文件和结构化的速度。我们假定数据已经被我们处理好了的情况。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>public static</span> <span style='color:rgba(100,149,237,1)'>void</span> <span style='color:rgba(255,0,255,1)'>CreateDic</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>string</span> strDicFile<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(100,149,237,1)'>string</span> strOutFile<span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>[]</span> by_temp <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(100,149,237,1)'>byte</span><span style='color:rgba(255,255,255,1)'>[</span><span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>];</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>using</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>FileStream</span> fs_out <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(0,255,255,1)'>FileStream</span><span style='color:rgba(255,255,255,1)'>(</span>strOutFile<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>FileMode</span><span style='color:rgba(112,128,144,1)'>.Create</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>FileAccess</span><span style='color:rgba(112,128,144,1)'>.Write</span><span style='color:rgba(255,255,255,1)'>)) {</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>using</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>StreamReader</span> reader <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(0,255,255,1)'>StreamReader</span><span style='color:rgba(255,255,255,1)'>(</span>strDicFile<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(255,255,255,1)'>)) {</span>
<span class='span_code_line'></span>            <span style='color:rgba(100,149,237,1)'>string</span> strLine <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(100,149,237,1)'>string</span><span style='color:rgba(112,128,144,1)'>.Empty</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>            <span style='color:rgba(30,144,255,1)'>while</span> <span style='color:rgba(255,255,255,1)'>((</span>strLine <span style='color:rgba(255,255,255,1)'>=</span> reader<span style='color:rgba(219,112,147,1)'>.ReadLine</span><span style='color:rgba(255,255,255,1)'>())</span> <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(30,144,255,1)'>null</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>                <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>strLine <span style='color:rgba(255,255,255,1)'>==</span> <span style='color:rgba(100,149,237,1)'>string</span><span style='color:rgba(112,128,144,1)'>.Empty</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>continue</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>                <span style='color:rgba(100,149,237,1)'>var</span> bytes <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>Encoding</span><span style='color:rgba(112,128,144,1)'>.UTF8</span><span style='color:rgba(219,112,147,1)'>.GetBytes</span><span style='color:rgba(255,255,255,1)'>(</span>strLine<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>                <span style='color:rgba(30,144,255,1)'>for</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>int</span> i <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span> i <span style='color:rgba(255,255,255,1)'>&lt;</span> bytes<span style='color:rgba(112,128,144,1)'>.Length</span> <span style='color:rgba(255,255,255,1)'>&amp;</span><span style='color:rgba(255,255,255,1)'>&amp;</span> i <span style='color:rgba(255,255,255,1)'>&lt;</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>;</span> i<span style='color:rgba(255,255,255,1)'>++</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>                    by_temp<span style='color:rgba(255,255,255,1)'>[</span>i<span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> bytes<span style='color:rgba(255,255,255,1)'>[</span>i<span style='color:rgba(255,255,255,1)'>];
<span class='span_code_line'></span>                }</span>
<span class='span_code_line'></span>                <span style='color:rgba(30,144,255,1)'>for</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(100,149,237,1)'>int</span> i <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> nLen <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>16</span> <span style='color:rgba(255,255,255,1)'>-</span> bytes<span style='color:rgba(112,128,144,1)'>.Length</span><span style='color:rgba(255,255,255,1)'>;</span> i <span style='color:rgba(255,255,255,1)'>&lt;</span> nLen<span style='color:rgba(255,255,255,1)'>;</span> i<span style='color:rgba(255,255,255,1)'>++</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>                    by_temp<span style='color:rgba(255,255,255,1)'>[</span>i <span style='color:rgba(255,255,255,1)'>+</span> bytes<span style='color:rgba(112,128,144,1)'>.Length</span><span style='color:rgba(255,255,255,1)'>]</span> <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>                }</span>
<span class='span_code_line'></span>                fs_out<span style='color:rgba(219,112,147,1)'>.Write</span><span style='color:rgba(255,255,255,1)'>(</span>by_temp<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> by_temp<span style='color:rgba(112,128,144,1)'>.Length</span><span style='color:rgba(255,255,255,1)'>);
<span class='span_code_line'></span>            }
<span class='span_code_line'></span>        }
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span>
<span class='span_code_line'></span><span style='color:rgba(0,255,0,1)'>// CreateDic("md5_test.txt","dic_new");</span></pre>
</div>
<p>我们直接结构化一个处理完毕的字典。。然后直接把这个字典往显存里面塞试试看。。。作者本来想直接使用下面的代码。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>File</span><span style='color:rgba(219,112,147,1)'>.ReadAllBytes</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(255,165,0,1)'>"dic_new"</span><span style='color:rgba(255,255,255,1)'>),</span> <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_STATIC_DRAW</span><span style='color:rgba(255,255,255,1)'>);</span></pre>
</div>
<p>可惜作者的电脑是个老古董，而且又是虚拟机。直接显存溢出了。。。所以还是得分批。。。</p>
<div class='div_code'>
<pre class='pre_code'><span class='span_code_line'></span><span style='color:rgba(30,144,255,1)'>using</span> <span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>FileStream</span> fs <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(30,144,255,1)'>new</span> <span style='color:rgba(0,255,255,1)'>FileStream</span><span style='color:rgba(255,255,255,1)'>(</span>strDic<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>FileMode</span><span style='color:rgba(112,128,144,1)'>.Open</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>FileAccess</span><span style='color:rgba(112,128,144,1)'>.Read</span><span style='color:rgba(255,255,255,1)'>)) {</span>
<span class='span_code_line'></span>    <span style='color:rgba(100,149,237,1)'>int</span> nLen <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>;</span>
<span class='span_code_line'></span>    <span style='color:rgba(30,144,255,1)'>while</span> <span style='color:rgba(255,255,255,1)'>((</span>nLen <span style='color:rgba(255,255,255,1)'>=</span> fs<span style='color:rgba(219,112,147,1)'>.Read</span><span style='color:rgba(255,255,255,1)'>(</span>by_buffer<span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> by_buffer<span style='color:rgba(112,128,144,1)'>.Length</span><span style='color:rgba(255,255,255,1)'>))</span> <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>) {</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.BufferSubData</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_ARRAY_BUFFER</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(0,255,255,1)'>IntPtr</span><span style='color:rgba(112,128,144,1)'>.Zero</span><span style='color:rgba(255,255,255,1)'>,</span> by_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        <span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(219,112,147,1)'>.DrawArrays</span><span style='color:rgba(255,255,255,1)'>(</span><span style='color:rgba(0,255,255,1)'>GL</span><span style='color:rgba(112,128,144,1)'>.GL_POINTS</span><span style='color:rgba(255,255,255,1)'>,</span> <span style='color:rgba(144,238,144,1)'>0</span><span style='color:rgba(255,255,255,1)'>,</span> nLen <span style='color:rgba(255,255,255,1)'>/</span> <span style='color:rgba(144,238,144,1)'>16</span><span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        strResult <span style='color:rgba(255,255,255,1)'>=</span> <span style='color:rgba(0,255,255,1)'>OpenGLMd5_1</span><span style='color:rgba(219,112,147,1)'>.GetResult</span><span style='color:rgba(255,255,255,1)'>(</span>b_arrs_result_buffer<span style='color:rgba(255,255,255,1)'>);</span>
<span class='span_code_line'></span>        <span style='color:rgba(30,144,255,1)'>if</span> <span style='color:rgba(255,255,255,1)'>(</span>strResult <span style='color:rgba(255,255,255,1)'>!=</span> <span style='color:rgba(30,144,255,1)'>null</span><span style='color:rgba(255,255,255,1)'>)</span> <span style='color:rgba(30,144,255,1)'>return</span> strResult<span style='color:rgba(255,255,255,1)'>;
<span class='span_code_line'></span>    }
<span class='span_code_line'></span>}</span></pre>
</div>
<p>为何我们之前拷贝进显存的数据都是使用的<span class='mark'>uint[]</span>类型，为什么这里用<span class='mark'>byte[]</span>？？是的没任何问题。而且上面也说了<span class='mark'>glBufferData</span>拷贝的数据无关数据类型。<span class='mark'>glVertexAttribPointer</span>告诉<span class='mark'>OpenGL</span>把他当做什么什么数据用及可以了。</p>
<img src='./images/new_result.png'/>
<p>可以看得速度几乎翻倍了。。当然是去掉了加载字典结构化的时间。而且可以的话，应该尽可能的一次拷贝更多的数据到显存中。<span style='color:pink'>当然<span class='mark'>OpenGL</span>的函数并不像一些高级语言一样如果出错会抛出<span class='mark'>Exception</span>，而是通过状态码的方式处理，当你执行某个函数后没有达到预期效果，可以在该函数后面执行<span class='mark'>glGetError</span>函数获取一个错误码。</span>对于异常的封装在<span class='mark'>STGL</span>中并没有完成。</p>
<p>所以说我们要如何优化加载字典的速度？？？醒醒老铁。。。这是一篇讲解如何用一种非主流的方式计算<span class='mark'>MD5</span>的文章，并不是一篇探讨<span class='mark'>IO</span>性能的文章。。。都写了这么长了。。再整下去就成连续剧了。。。如果实在要继续的话。。🤔🤔🤔。。</p>
<img src='./images/money.png'/>
<p>项目(OpenGLForHash)地址: <a class='mark' target='_blank' href='https://github.com/DebugST/OpenGLForHash'>GitHub</a> <a class='mark' target='_blank' href='https://gitee.com/DebugST/OpenGLForHash'>Gitee</a></p>

</div>
<div id="div_right_list">
<a name='a_a' href='#a_a'>密码碰撞可以有多非主流？</a>
<a name='a_b' href='#a_b'>起因</a>
<a name='a_c' href='#a_c'>OpenGL简介</a>
<a name='a_d' href='#a_d'>图形渲染管线</a>
<a name='a_e' href='#a_e'>着色器</a>
<a name='a_f' href='#a_f'>你好三角形</a>
<a name='a_g' href='#a_g'>思路分析</a>
<a name='a_h' href='#a_h'>MD5算法</a>
<a name='a_i' href='#a_i'>计算过程</a>
<a name='a_j' href='#a_j'>批量计算</a>
<a name='a_k' href='#a_k'>试验效果</a>
<a name='a_l' href='#a_l'>优化方案</a>
</div>
</div>
</body>
</html>
